/**
 * @file 	CFGTester.java
 * 
 * @date 	2/23/2012
 * 
 * @author 	Aaron Alaniz (aaron.a.alaniz@gmail.com)
 * 
 * @brief	This class provides unit tests for code written for Pair.java
 * 			and ControlFlowGraph.java. Running all of these tests provides
 * 			statement coverage for code in these classes.
 *
 */

import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;

public class CFGTester {
	
	Pair nullPair, p1, p2, p3, p4;
	String testString;
	ControlFlowGraph.Node n1, n2, n3;
	ControlFlowGraph cfg;
	
	@Before public void setUp() {
		
		// Create pairs for testing Pair code
		nullPair = null;
		p1 = new Pair<Integer, String>(new Integer(5), new String("Test String 2"));
		p2 = new Pair<String, Integer>(new String("Test String 2"), new Integer(5));
		p3 = new Pair<Integer, String>(new Integer(5), new String("Test String 2"));
		
		// Create dummy string
		testString = new String("hello");
		
		// Create nodes for testing
		n1 = new ControlFlowGraph.Node("C", "m", 1);
		n2 = new ControlFlowGraph.Node("C", "m", 2);
		n3 = new ControlFlowGraph.Node("C", "m", 1);
		
		// Create a control flow graph
		cfg = new ControlFlowGraph();
	}
	
	// Pair testing
	@Test public void pairTest() { 
		assertTrue(p1.one().equals(p2.two())); // test Pair one and two methods
		assertTrue(p1.toString().equals(p3.toString())); // test Pair toString method
		assertTrue(p1.equals(p3)); // test Pair equals success
		assertFalse(p1.equals(nullPair)); // test Pair equals failure for null 
		assertFalse(p1.equals(testString)); // test Pair equals failure for differing objects
		assertTrue(p1.hashCode() == p3.hashCode()); // test Pair hashcode implementation
	}
	
	@Test public void nodeTest() { 
		assertFalse(n1.toString().equals(n2.toString())); // test Node toString method
		assertTrue(n1.equals(n3)); // test Node equals success
		assertFalse(n1.equals(null)); // test Node equals failure for null
		assertFalse(n1.equals(p1)); // test Node equals for differing objects
		assertTrue(n1.hashCode() == n3.hashCode()); // test Node hashcode implementation
	}
	
	@Test public void cfgAddNodeTest() {
		cfg.addNode(n1.classname, n1.methodname, n1.id); // execute CFG add node
		
		// Verify results
		assertTrue(cfg.nodes.contains(n1) == true);
		assertTrue(cfg.edges.containsKey(n1) == true);
		assertTrue(cfg.edges.get(n1).isEmpty() == true);
	}
	
	@Test public void cfgAddEdgeTest() {
		cfg.addEdge("C", "m", n1.id, n2.id); // execute all three add edge implementations with this call
		assertTrue(cfg.edges.get(n1).isEmpty() == false); // verify result
	}
	
	@Test public void cfgReachabilityTest() {
		
		// Populate an example graph
		cfg.addNode("C", "m", 0);
		cfg.addNode("C", "m", 1);
		cfg.addNode("C", "m", 2);
		cfg.addNode("C", "m", 3);
		cfg.addNode("C", "m", 4);
		cfg.addNode("C", "m", 5);
		cfg.addNode("C", "m", 6);
		
		// Create edges between nodes
		cfg.addEdge("C", "m", 0, 1);
		cfg.addEdge("C", "m", 0, 2);
		cfg.addEdge("C", "m", 1, 3);
		cfg.addEdge("C", "m", 3, 6);
		cfg.addEdge("C", "m", 2, 4);
		cfg.addEdge("C", "m", 3, 5);
		cfg.addEdge("C", "m", 4, 5);
		
		// Verify reachable
		assertTrue(cfg.reachable("C", "m", 0, "C", "m", 5)); // guaranteed to cover all of the "if" clause
		assertTrue(cfg.reachable("C", "m", 0, "C", "m", 0)); // cover identical start and destination node
		assertFalse(cfg.reachable("C", "m", 3, "C", "m", 4)); // covers returning false on search
		assertFalse(cfg.reachable("C", "m", 5, "C", "m", 0));
		
		// Verify allNodesReachable
		assertTrue(cfg.allNodesReachable("C", "m", 0)); // test success case
		assertFalse(cfg.allNodesReachable("C", "m", 1)); // test failure case
		
		String cfgString = cfg.toString(); // cover toString method
	}

}